﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web.Mvc;
using System.Web.Routing;
using System.Web;
using System.Globalization;

namespace LiteExpress.Core.Web.MVC.Themes
{
    public class VirtualPathViewEngine : VirtualPathProviderViewEngine
    {
        private readonly string[] _emptyLocations = null;

        public delegate string GetCurrentThemeHandler();
        public GetCurrentThemeHandler ThemeHandler;

        //public VirtualPathViewEngine()
        //{
        //    AreaViewLocationFormats = new[]
        //                                  {
        //                                      //themes
        //                                      "~/Areas/{2}/Themes/{3}/Views/{1}/{0}.cshtml", 
        //                                      "~/Areas/{2}/Themes/{3}/Views/{1}/{0}.vbhtml", 
        //                                      "~/Areas/{2}/Themes/{3}/Views/Shared/{0}.cshtml", 
        //                                      "~/Areas/{2}/Themes/{3}/Views/Shared/{0}.vbhtml",
                                              
        //                                      //default
        //                                      "~/Areas/{2}/Views/{1}/{0}.cshtml", 
        //                                      "~/Areas/{2}/Views/{1}/{0}.vbhtml", 
        //                                      "~/Areas/{2}/Views/Shared/{0}.cshtml", 
        //                                      "~/Areas/{2}/Views/Shared/{0}.vbhtml"
        //                                  };

        //    AreaMasterLocationFormats = new[]
        //                                    {
        //                                        //themes
        //                                        "~/Areas/{2}/Themes/{3}/Views/{1}/{0}.cshtml", 
        //                                        "~/Areas/{2}/Themes/{3}/Views/{1}/{0}.vbhtml", 
        //                                        "~/Areas/{2}/Themes/{3}/Views/Shared/{0}.cshtml", 
        //                                        "~/Areas/{2}/Themes/{3}/Views/Shared/{0}.vbhtml",


        //                                        //default
        //                                        "~/Areas/{2}/Views/{1}/{0}.cshtml", 
        //                                        "~/Areas/{2}/Views/{1}/{0}.vbhtml", 
        //                                        "~/Areas/{2}/Views/Shared/{0}.cshtml", 
        //                                        "~/Areas/{2}/Views/Shared/{0}.vbhtml"
        //                                    };

        //    AreaPartialViewLocationFormats = new[]
        //                                         {
        //                                             //themes
        //                                            "~/Areas/{2}/Themes/{3}/Views/{1}/{0}.cshtml", 
        //                                            "~/Areas/{2}/Themes/{3}/Views/{1}/{0}.vbhtml", 
        //                                            "~/Areas/{2}/Themes/{3}/Views/Shared/{0}.cshtml", 
        //                                            "~/Areas/{2}/Themes/{3}/Views/Shared/{0}.vbhtml",
                                                    
        //                                            //default
        //                                            "~/Areas/{2}/Views/{1}/{0}.cshtml", 
        //                                            "~/Areas/{2}/Views/{1}/{0}.vbhtml", 
        //                                            "~/Areas/{2}/Views/Shared/{0}.cshtml", 
        //                                            "~/Areas/{2}/Views/Shared/{0}.vbhtml"
        //                                         };

        //    ViewLocationFormats = new[]
        //                              {
        //                                    //themes
        //                                    "~/Themes/{2}/Views/{1}/{0}.cshtml", 
        //                                    "~/Themes/{2}/Views/{1}/{0}.vbhtml", 
        //                                    "~/Themes/{2}/Views/Shared/{0}.cshtml",
        //                                    "~/Themes/{2}/Views/Shared/{0}.vbhtml",

        //                                    //default
        //                                    "~/Views/{1}/{0}.cshtml", 
        //                                    "~/Views/{1}/{0}.vbhtml", 
        //                                    "~/Views/Shared/{0}.cshtml",
        //                                    "~/Views/Shared/{0}.vbhtml"
        //                              };

        //    MasterLocationFormats = new[]
        //                                {
        //                                    //themes
        //                                    "~/Themes/{2}/Views/{1}/{0}.cshtml", 
        //                                    "~/Themes/{2}/Views/{1}/{0}.vbhtml", 
        //                                    "~/Themes/{2}/Views/Shared/{0}.cshtml", 
        //                                    "~/Themes/{2}/Views/Shared/{0}.vbhtml",

        //                                    //default
        //                                    "~/Views/{1}/{0}.cshtml", 
        //                                    "~/Views/{1}/{0}.vbhtml", 
        //                                    "~/Views/Shared/{0}.cshtml", 
        //                                    "~/Views/Shared/{0}.vbhtml"
        //                                };

        //    PartialViewLocationFormats = new[]
        //                                     {
        //                                         //themes
        //                                        "~/Themes/{2}/Views/{1}/{0}.cshtml", 
        //                                        "~/Themes/{2}/Views/{1}/{0}.vbhtml", 
        //                                        "~/Themes/{2}/Views/Shared/{0}.cshtml", 
        //                                        "~/Themes/{2}/Views/Shared/{0}.vbhtml",

        //                                        //default
        //                                        "~/Views/{1}/{0}.cshtml", 
        //                                        "~/Views/{1}/{0}.vbhtml", 
        //                                        "~/Views/Shared/{0}.cshtml", 
        //                                        "~/Views/Shared/{0}.vbhtml",
        //                                     };
        //}

        public VirtualPathViewEngine(GetCurrentThemeHandler themeHandler)
        {
            ThemeHandler = themeHandler;
            AreaViewLocationFormats = new[]
                                          {
                                              //themes
                                              "~/Areas/{2}/Themes/{3}/Views/{1}/{0}.cshtml", 
                                              "~/Areas/{2}/Themes/{3}/Views/{1}/{0}.vbhtml", 
                                              "~/Areas/{2}/Themes/{3}/Views/Shared/{0}.cshtml", 
                                              "~/Areas/{2}/Themes/{3}/Views/Shared/{0}.vbhtml",
                                              
                                              //default
                                              "~/Areas/{2}/Views/{1}/{0}.cshtml", 
                                              "~/Areas/{2}/Views/{1}/{0}.vbhtml", 
                                              "~/Areas/{2}/Views/Shared/{0}.cshtml", 
                                              "~/Areas/{2}/Views/Shared/{0}.vbhtml"
                                          };

            AreaMasterLocationFormats = new[]
                                            {
                                                //themes
                                                "~/Areas/{2}/Themes/{3}/Views/{1}/{0}.cshtml", 
                                                "~/Areas/{2}/Themes/{3}/Views/{1}/{0}.vbhtml", 
                                                "~/Areas/{2}/Themes/{3}/Views/Shared/{0}.cshtml", 
                                                "~/Areas/{2}/Themes/{3}/Views/Shared/{0}.vbhtml",


                                                //default
                                                "~/Areas/{2}/Views/{1}/{0}.cshtml", 
                                                "~/Areas/{2}/Views/{1}/{0}.vbhtml", 
                                                "~/Areas/{2}/Views/Shared/{0}.cshtml", 
                                                "~/Areas/{2}/Views/Shared/{0}.vbhtml"
                                            };

            AreaPartialViewLocationFormats = new[]
                                                 {
                                                     //themes
                                                    "~/Areas/{2}/Themes/{3}/Views/{1}/{0}.cshtml", 
                                                    "~/Areas/{2}/Themes/{3}/Views/{1}/{0}.vbhtml", 
                                                    "~/Areas/{2}/Themes/{3}/Views/Shared/{0}.cshtml", 
                                                    "~/Areas/{2}/Themes/{3}/Views/Shared/{0}.vbhtml",
                                                    
                                                    //default
                                                    "~/Areas/{2}/Views/{1}/{0}.cshtml", 
                                                    "~/Areas/{2}/Views/{1}/{0}.vbhtml", 
                                                    "~/Areas/{2}/Views/Shared/{0}.cshtml", 
                                                    "~/Areas/{2}/Views/Shared/{0}.vbhtml"
                                                 };

            ViewLocationFormats = new[]
                                      {
                                            //themes
                                            "~/Themes/{2}/Views/{1}/{0}.cshtml", 
                                            "~/Themes/{2}/Views/{1}/{0}.vbhtml", 
                                            "~/Themes/{2}/Views/Shared/{0}.cshtml",
                                            "~/Themes/{2}/Views/Shared/{0}.vbhtml",

                                            //default
                                            "~/Views/{1}/{0}.cshtml", 
                                            "~/Views/{1}/{0}.vbhtml", 
                                            "~/Views/Shared/{0}.cshtml",
                                            "~/Views/Shared/{0}.vbhtml"
                                      };

            MasterLocationFormats = new[]
                                        {
                                            //themes
                                            "~/Themes/{2}/Views/{1}/{0}.cshtml", 
                                            "~/Themes/{2}/Views/{1}/{0}.vbhtml", 
                                            "~/Themes/{2}/Views/Shared/{0}.cshtml", 
                                            "~/Themes/{2}/Views/Shared/{0}.vbhtml",

                                            //default
                                            "~/Views/{1}/{0}.cshtml", 
                                            "~/Views/{1}/{0}.vbhtml", 
                                            "~/Views/Shared/{0}.cshtml", 
                                            "~/Views/Shared/{0}.vbhtml"
                                        };

            PartialViewLocationFormats = new[]
                                             {
                                                 //themes
                                                "~/Themes/{2}/Views/{1}/{0}.cshtml", 
                                                "~/Themes/{2}/Views/{1}/{0}.vbhtml", 
                                                "~/Themes/{2}/Views/Shared/{0}.cshtml", 
                                                "~/Themes/{2}/Views/Shared/{0}.vbhtml",

                                                //default
                                                "~/Views/{1}/{0}.cshtml", 
                                                "~/Views/{1}/{0}.vbhtml", 
                                                "~/Views/Shared/{0}.cshtml", 
                                                "~/Views/Shared/{0}.vbhtml",
                                             };
        }

        protected override IView CreatePartialView(ControllerContext controllerContext, string partialPath)
        {
            string layoutPath = null;
            var runViewStartPages = false;
            IEnumerable<string> fileExtensions = base.FileExtensions;
            return new RazorView(controllerContext, partialPath, layoutPath, runViewStartPages, fileExtensions);
            //return new RazorView(controllerContext, partialPath, layoutPath, runViewStartPages, fileExtensions, base.ViewPageActivator);
        }

        protected override IView CreateView(ControllerContext controllerContext, string viewPath, string masterPath)
        {
            string layoutPath = masterPath;
            var runViewStartPages = true;
            IEnumerable<string> fileExtensions = base.FileExtensions;
            return new RazorView(controllerContext, viewPath, layoutPath, runViewStartPages, fileExtensions);
        }

        //protected override bool FileExists(ControllerContext controllerContext, string virtualPath)
        //{
        //    return BuildManager.GetObjectFactory(virtualPath, false) != null;
        //}

        public override ViewEngineResult FindPartialView(ControllerContext controllerContext, string partialViewName, bool useCache)
        {
            string[] strArray;
            if (controllerContext == null)
            {
                throw new ArgumentNullException("controllerContext");
            }
            if (string.IsNullOrEmpty(partialViewName))
            {
                throw new ArgumentException("Partial view name cannot be null or empty.", "partialViewName");
            }
            var theme = ThemeHandler();
            string requiredString = controllerContext.RouteData.GetRequiredString("controller");
            string str2 = this.GetPath(controllerContext, this.PartialViewLocationFormats, this.AreaPartialViewLocationFormats, "PartialViewLocationFormats", partialViewName, requiredString, theme, "Partial", useCache, out strArray);
            if (string.IsNullOrEmpty(str2))
            {
                return new ViewEngineResult(strArray);
            }
            return new ViewEngineResult(this.CreatePartialView(controllerContext, str2), this);
        }

        public override ViewEngineResult FindView(ControllerContext controllerContext, string viewName, string masterName, bool useCache)
        {
            string[] strArray;
            string[] strArray2;
            var theme = ThemeHandler();
            string requiredString = controllerContext.RouteData.GetRequiredString("controller");
            string str2 = this.GetPath(controllerContext, this.ViewLocationFormats, this.AreaViewLocationFormats, "ViewLocationFormats", viewName, requiredString, theme, "View", useCache, out strArray);
            string str3 = this.GetPath(controllerContext, this.MasterLocationFormats, this.AreaMasterLocationFormats, "MasterLocationFormats", masterName, requiredString, theme, "Master", useCache, out strArray2);
            if (!string.IsNullOrEmpty(str2) && (!string.IsNullOrEmpty(str3) || string.IsNullOrEmpty(masterName)))
            {
                return new ViewEngineResult(this.CreateView(controllerContext, str2, str3), this);
            }
            if (strArray2 == null)
            {
                strArray2 = new string[0];
            }
            return new ViewEngineResult(strArray.Union<string>(strArray2));
        }

        protected string GetPath(ControllerContext controllerContext, string[] locations, string[] areaLocations, string locationsPropertyName, string name, string controllerName, string theme, string cacheKeyPrefix, bool useCache, out string[] searchedLocations)
        {
            searchedLocations = _emptyLocations;
            if (string.IsNullOrEmpty(name))
            {
                return string.Empty;
            }
            string areaName = GetAreaName(controllerContext.RouteData);

            bool flag = !string.IsNullOrEmpty(areaName);
            List<ViewLocation> viewLocations = GetViewLocations(locations, flag ? areaLocations : null);
            if (viewLocations.Count == 0)
            {
                throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, "Properties cannot be null or empty.", new object[] { locationsPropertyName }));
            }
            bool flag2 = IsSpecificPath(name);
            string key = this.CreateCacheKey(cacheKeyPrefix, name, flag2 ? string.Empty : controllerName, areaName, theme);
            if (useCache)
            {
                var cached = this.ViewLocationCache.GetViewLocation(controllerContext.HttpContext, key);
                if (cached != null)
                {
                    return cached;
                }
            }
            if (!flag2)
            {
                return this.GetPathFromGeneralName(controllerContext, viewLocations, name, controllerName, areaName, theme, key, ref searchedLocations);
            }
            return this.GetPathFromSpecificName(controllerContext, name, key, ref searchedLocations);
        }

        protected string CreateCacheKey(string prefix, string name, string controllerName, string areaName, string theme)
        {
            return string.Format(CultureInfo.InvariantCulture, ":ViewCacheEntry:{0}:{1}:{2}:{3}:{4}:{5}", new object[] { base.GetType().AssemblyQualifiedName, prefix, name, controllerName, areaName, theme });
        }

        protected string GetPathFromGeneralName(ControllerContext controllerContext, List<ViewLocation> locations, string name, string controllerName, string areaName, string theme, string cacheKey, ref string[] searchedLocations)
        {
            string virtualPath = string.Empty;
            searchedLocations = new string[locations.Count];
            for (int i = 0; i < locations.Count; i++)
            {
                string str2 = locations[i].Format(name, controllerName, areaName, theme);
                if (this.FileExists(controllerContext, str2))
                {
                    searchedLocations = _emptyLocations;
                    virtualPath = str2;
                    this.ViewLocationCache.InsertViewLocation(controllerContext.HttpContext, cacheKey, virtualPath);
                    return virtualPath;
                }
                searchedLocations[i] = str2;
            }
            return virtualPath;
        }

        protected string GetPathFromSpecificName(ControllerContext controllerContext, string name, string cacheKey, ref string[] searchedLocations)
        {
            string virtualPath = name;
            if (!this.FilePathIsSupported(name) || !this.FileExists(controllerContext, name))
            {
                virtualPath = string.Empty;
                searchedLocations = new string[] { name };
            }
            this.ViewLocationCache.InsertViewLocation(controllerContext.HttpContext, cacheKey, virtualPath);
            return virtualPath;
        }

        protected bool FilePathIsSupported(string virtualPath)
        {
            if (this.FileExtensions == null)
            {
                return true;
            }
            string str = VirtualPathUtility.GetExtension(virtualPath).TrimStart(new char[] { '.' });
            return this.FileExtensions.Contains<string>(str, StringComparer.OrdinalIgnoreCase);
        }


        //public string GetCurrentTheme()
        //{
        //    //throw new NotImplementedException();
        //    return "Mobile";
        //}

        protected string GetAreaName(RouteData routeData)
        {
            object obj2;
            if (routeData.DataTokens.TryGetValue("area", out obj2))
            {
                return (obj2 as string);
            }
            return GetAreaName(routeData.Route);
        }

        protected string GetAreaName(RouteBase route)
        {
            var area = route as IRouteWithArea;
            if (area != null)
            {
                return area.Area;
            }
            var route2 = route as Route;
            if ((route2 != null) && (route2.DataTokens != null))
            {
                return (route2.DataTokens["area"] as string);
            }
            return null;
        }

        protected List<ViewLocation> GetViewLocations(string[] viewLocationFormats, string[] areaViewLocationFormats)
        {
            var list = new List<ViewLocation>();
            if (areaViewLocationFormats != null)
            {
                list.AddRange(areaViewLocationFormats.Select(str => new AreaAwareViewLocation(str)).Cast<ViewLocation>());
            }
            if (viewLocationFormats != null)
            {
                list.AddRange(viewLocationFormats.Select(str2 => new ViewLocation(str2)));
            }
            return list;
        }

        protected bool IsSpecificPath(string name)
        {
            char ch = name[0];
            if (ch != '~')
            {
                return (ch == '/');
            }
            return true;
        }

    }

}
